/***************************************************************************
 *   Copyright (C) 2004 - 2007 by Moritz Vieth                             *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef INCLUDED_DEBUG_H
#define INCLUDED_DEBUG_H


#include <string>
#include <vector>


/**
 * This class provides useful methods for managing textual output of your
 * application.
 * 
 * Each call of the messaging (#message and #hexdump) and logging (#log)
 * methods will get you some nicely formatted output. For any of these calls,
 * a debug level has to be specified. If this level does not exceed a given
 * threshold (as set by #setDebugLevel and #setLogLevel), the message will
 * be discarded.
 * All output is completely threadsafe (no more 'stdout salad' by multiple
 * threads. Yeah!).
 * 
 * Each message call will result in a log call as well.
 * Messages with levels IMPORTANT and CRITICAL will be written to error.log,
 * all other to debug.log
 * 
 * There are several properties of the class that can be configured by
 * calling the appropriate methods:
 * 
 * setLevel(int): 		sets the threshold for the textual (i.e. terminal)
 * 						output
 * 
 * setLogLevel(int): 	sets the threshold for the logging output.
 * 
 * setQuiet():			surpress ALL output
 * 
 * setTag(string):		sets the application tag to print at the beginning of
 * 						each line, e.g. setTag("myApp") will result in:
 * 						[myApp] [DEBUG] <some debug message>
 * 
 * setApplicationInfo(string): Info (like version, build date etc) to print at
 * 						the beginning of each logging session
 * 
 * setLogPath(string):	sets the path where to store your log files.
 * 
 * showFunctionNames(bool): specifies wether to print the function name where
 * 						the message call oroginated from or not. E.g.:
 * 						[myApp] [DEBUG] MyClass::someFunction: some debug message 
 * 						This is nice when debugging, but rather annoying on 
 * 						"normal" runs.
 * 						For this to work, the program has to be compiled using the
 * 						-pg flag 
 * 
 * showParams(bool):	set wether function parameters shall be printed (when
 * 						printing function names, otherwise ignored). E.g.:
 * 						[myApp] [DEBUG] MyClass::someFunction(int,string): some debug message
 * 
 * addFunctionFilterString(string): adds strings to filter when displaying
 * 						function names. This is useful for instance when using
 * 						Qt applications, which will surround you "original" program
 * 						whith loads of wrappers. 
 * 						*** EXPERIMENTAL ***
 * 
 * USAGE:
 * just #include <Debug.h> and call the static functions, e.g.
 * Debug::setTag("SomeApp");
 * Debug::showFunctionNames(false);
 * Debug::message("Postion: (%d,%d)", Debug::TESTING, pos.x, pos.y);
 *   
 * will result in
 * [SomeApp] [DEBUG] Position: (120,340)
 * (or whatever 'pos' is...)
 * 
 * 
 * 
 * The output methods are:
 * 
 * message(string[, int]):	prints message to stdout. Level does not need to be given,
 * 							default is DEBUG
 * message(char* , int, ...): prints message to stdout, the good old printf way! (Debug
 * 							level has to be the first parameter after the format string)
 * 
 * log(string[, int]):		same as above for logging.
 * log(char*, int, ...):	same as above for logging.
 * 
 * seperator(string[, int]):
 * seperator([int]):		prints a seperating line to stdout (without tags etc.).
 * 							Useful when working with (infinite) loops.
 * 							A different seperatot than the standard one can be specified.
 * 
 * hexdump(string, uchar*, int, int, int):
 * 							hexdumps a byte array (e.g. an IP packet). The string is a
 * 							description for the array, width specifies how many bytes
 * 							per line should be printed. Rest should be self-explanatory ;)
 * 
 * printBacktrace(int[, int]):
 * printBacktrace(string, int[, int]):
 * 							As the name suggests, this prints a backtrace to stdout (leaving out
 * 							the Methods of this class), along with on (optional) note.
 * 							Optionally, you can specify if and how many level of the backtrace should
 * 							be left out, for instance to exclude the calling method.
 * 
 * 
 * NOTE:
 * printBacktrace can be used conveniently to automatically do a backtrace after recieving
 * a segmentation fault.
 * This can be done by adding the following to the file containing your main method
 ** #include <signal.h>
 ** 
 ** void term_func(int signal){
 ** 		Debug::printBacktrace("Recieved Segmentation fault!", Debug::CRITICAL, 2);
 ** 		exit(1);
 ** }
 ** 
 ** int main(){
 ** ...
 ** signal(SIGSEGV, term_func);
 ** ...
 ** }
 * 
 * The same can be done for any signal, of course. 
 * 
 * 						
 * 
 * @author Moritz Vieth
 * @version 1.5
 */
class Debug
{
	
public:
  static const int DEBUG;
  static const int TESTING;
  static const int VERBOSE;
  static const int IMPORTANT;
  static const int CRITICAL;
  
  
  static void message(std::string msg, int level = Debug::DEBUG);
  static void message(char* msg, int level, ...);
  
  static void log(std::string msg, int level = Debug::DEBUG);
  static void log(char* msg, int level, ...);
  
  static void hexdump(std::string type, unsigned char* data, int length, int width, int level);

  static void printBacktrace(int level = Debug::DEBUG, int stripLevels = 0);
  static void printBacktrace(std::string note, int level = Debug::DEBUG, int stripLevels = 0);
  
  static void seperator(std::string sep, int level = Debug::DEBUG);
  static void seperator(int level = Debug::DEBUG);
  
  
  
  static void setLevel(int level);
  static void setLogLevel(int level);
  static void setQuiet();
  static void setLogQuiet();
  
  static void setTag(std::string tag);
  static void setApplicationInfo(std::string info);
  
  static void setLogPath(std::string path);
  
  static void writeToDebugLog(std::string text);
  static void writeToErrorLog(std::string text);
  
  
  
  static int getLevel();
  
  static inline void addFunctionFilterString(std::string filter){
  		Debug::functionNameFilter->push_back(filter);
  }
  
  static inline void showParams(bool doIt){
  		Debug::doShowParams = doIt;
  }
  
  static inline void showFunctionNames(bool doIt){
  		Debug::doShowFunctionNames = doIt;
  }
  
  static inline void showLineNumbers(bool doIt){
  		Debug::doShowLineNumbers = doIt;
  }
  
  static inline void showFileNames(bool doIt){
  		Debug::doShowFileNames = doIt;
  }
  
  
  
	

private:
  static int level;
  static int logLevel;
  static int highestLevel;
  static std::string tag;
  static std::string applicationInfo;
  
  static std::ofstream* debugLog;
  static std::ofstream* errorLog;
  
  static std::string logPath;
  static std::string fullDebugLogPath;
  static std::string fullErrorLogPath;
  
  static std::string debugLogName;
  static std::string errorLogName;
  
  static bool alreadyLogged;
  
  static void startLog(std::string info = "[no Info]");
  
  /*static pthread_mutex_t debugLock;
  static pthread_mutex_t errorLock;
  static pthread_mutex_t outputLock;*/
  
  
  static bool doShowParams;
  static bool doShowFunctionNames;
  static bool doShowFileNames;
  static bool doShowLineNumbers;
  
  static std::vector<std::string>* functionNameFilter;
  
  static std::string getCaller();
  
  
};

#endif /*!INCLUDED_DEBUG_H*/
